package com.xjtu.mybatisplus.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xjtu.mybatisplus.common.constant.RedisConstant;
import com.xjtu.mybatisplus.common.result.PageResult;
import com.xjtu.mybatisplus.common.utls.RedisUtil;
import com.xjtu.mybatisplus.mapper.CommentMapper;
import com.xjtu.mybatisplus.mapper.UserMapper;
import com.xjtu.mybatisplus.model.domain.Article;
import com.xjtu.mybatisplus.mapper.ArticleMapper;
import com.xjtu.mybatisplus.model.domain.Comment;
import com.xjtu.mybatisplus.model.esdocument.ESArticle;
import com.xjtu.mybatisplus.service.ArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjtu.mybatisplus.service.ReviewService;
import com.xjtu.mybatisplus.service.es.EsArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lsong
 * @since 2023-12-27
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ReviewService reviewService;

    @Autowired
    private EsArticleService esArticleService;

    @Autowired(required = false)
    private CommentMapper commentMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${review.phaseNum}")
    Integer phaseNum;

    @Override
    public List<Article> getList() {

        return null;
    }

    @Override
    public boolean removeById(Long id) {
        esArticleService.deleteArticle(String.valueOf(id));
        return super.removeById(id);
    }

    @Autowired
    private UserMapper userService;
    @Override
    public List<Article> listByUserId(Long userId) {
        Long userRole = userService.getUserRole(userId);
        if (userRole == 4) {
            return articleMapper.selectList(null);
        }
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getUserId, userId);
        return articleMapper.selectList(queryWrapper);
    }

    @Override
    public void saveArticle(Article article) {
        article.setStatus(-2);
        if (article.getId() == null) {
            articleMapper.insert(article);
        } else {
            articleMapper.updateById(article);
        }
        esArticleService.saveArticle(ESArticle.fromArticle(article));
    }

    @Override
    public void audit(Long id) {
        UpdateWrapper<Article> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("status", 0);
        articleMapper.update(null, updateWrapper);
        reviewService.insert(id, 1);
    }

    @Override
    public List<Article> auditList(Long userId) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getUserId, userId).ne(Article::getStatus, -2);
        return articleMapper.selectList(queryWrapper);
    }

    @Override
    public void withdraw(Long id) {
        UpdateWrapper<Article> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("status", -2);
        articleMapper.update(null, updateWrapper);
        reviewService.resetReview(id);
    }

    @Override
    public PageResult getNewestArtical(Integer page, Integer size) {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.eq("status", phaseNum);
        wrapper.eq("is_deleted", 0);
        wrapper.orderByDesc("publish_time");
        Page<Article> articlePage = articleMapper.selectPage(new Page<>(page, size), wrapper);
        List<Article> records = articlePage.getRecords();
        PageResult result = new PageResult();
        result.setItems(records);
        result.setTotal(articlePage.getTotal());
        return result;
    }

    @Override
    public PageResult getArticalByCate(Integer page, Integer size, Integer cate) {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.eq("status", phaseNum);
        wrapper.eq("is_deleted", 0);
        wrapper.orderByDesc("publish_time");
        wrapper.eq("category_id", cate);
        Page<Article> articlePage = articleMapper.selectPage(new Page<>(page, size), wrapper);
        List<Article> records = articlePage.getRecords();
        PageResult result = new PageResult();
        result.setItems(records);
        result.setTotal(articlePage.getTotal());
        return result;
    }

    @Override
    public List<Article> getHotArtical() {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.eq("status", phaseNum);
        wrapper.eq("is_deleted", 0);
        wrapper.orderByDesc("watch");
        try {
            List<Article> resp = getHots();
            if (resp != null && resp.size() != 0) {
                return resp;
            }
            Page<Article> articlePage = articleMapper.selectPage(new Page<>(1, 10), wrapper);
            List<Article> records = articlePage.getRecords();
            hotSort(records);
            List<Article> result = getHots();
            return result;
        } catch (Exception e) {
            Page<Article> articlePage = articleMapper.selectPage(new Page<>(1, 10), wrapper);
            return articlePage.getRecords();
        }
    }


    public List<Article> getHots() {
        String key = RedisConstant.HOT_ARTICALS;
        // 获取按热度排序的所有文章，从高到低
        Set<Object> hotArticlesSet = redisTemplate.opsForZSet().reverseRange(key, 0, -1);
        // Use Java Streams to filter and cast the elements
        List<Article> hotArticlesList = hotArticlesSet.stream()
                .filter(Article.class::isInstance)
                .map(Article.class::cast)
                .collect(Collectors.toList());
        return hotArticlesList;
    }

    public void hotSort(List<Article> list) {
        //  把热门数据放入redis
        list.forEach(article -> {
            // 获取每一篇文章在redis中的浏览量
            String key = "articleId_" + article.getId();
            Long view = redisUtil.size(key);
            view = view + article.getWatch();
            // 获取每一篇文章的点赞数
            QueryWrapper<Comment> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("article_id", article.getId());
            queryWrapper.eq("is_deleted", 0);
            Integer like = commentMapper.selectCount(queryWrapper);
            article.setHot(Math.toIntExact(view) * 25 + like * 75);
        });
        // 这里要对文章进综合评分和排序
        String key = RedisConstant.HOT_ARTICALS;
        // 将文章列表存储到 Redis 有序集合中，按照 hot 值进行排序
        for (Article article : list) {
            redisTemplate.opsForZSet().add(key, article, article.getHot());
        }
        // 设置过期时间
        redisTemplate.expire(key, 30, TimeUnit.MINUTES);
    }

    @Override
    public List<Long> getAllArticleId() {
        List<Long> resp = articleMapper.getAllIds();
        return resp;
    }

    public Article getPublishedArticle(Long id) {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 2);
        wrapper.eq("is_deleted", 0);
        wrapper.eq("id", id);
        return articleMapper.selectOne(wrapper);
    }
}
